<template>
	<view class="page">
		<view class="brand-header"></view>
		<view class="card card-hover" style="margin-top:-80rpx; padding:24rpx 20rpx;">
			<view class="header">
				<text class="title">MBTI 测评</text>
				<view class="level">
					<text class="sub">题量：</text>
					<picker :range="levels" :value="levelIndex" @change="e=>levelIndex=e.detail.value">
						<view class="picker">{{ levelLabel }}</view>
					</picker>
				</view>
				<text class="sub">五点量表：非常不同意 → 非常同意</text>
			</view>
			<!-- 粘性进度条 -->
			<view class="progress progress-sticky" v-if="questions.length">
				<text class="progress-text">已答 {{ answeredCount }}/{{ questions.length }}</text>
				<view class="progress-track"><view class="progress-fill" :style="{ width: progressPct + '%' }"></view></view>
			</view>
			<view v-if="loading" class="loading">正在加载题库...</view>
			<view v-else>
				<view v-for="(q, idx) in questions" :key="q.id" :class="['q-card','card-hover', answers[q.id] ? 'answered' : '']" :id="'q_'+q.id">
					<view class="q-head">
						<view class="badge">{{ idx + 1 }}</view>
						<text class="q-text">{{ q.text }}</text>
					</view>
					<radio-group class="scale" @change="onAnswerChange(q.id, $event.detail.value)">
						<label v-for="v in [1,2,3,4,5]" :key="v" class="scale-item">
							<radio class="scale-radio" :value="String(v)" :checked="answers[q.id] == String(v)" />
							<text class="chip" :class="{ active: answers[q.id] == String(v) }">{{ scaleLabel(v) }}</text>
						</label>
					</radio-group>
				</view>
				<view class="actions safe-bottom">
					<button class="btn btn-primary btn-pill btn-wide" :loading="submitting" :disabled="!allAnswered || submitting" @click="submit">提交并查看结果</button>
				</view>
			</view>
		</view>
		<!-- 悬浮操作：回顶 / 下一未答 -->
		<view class="fab">
			<button class="fab-btn" @click="goTop">↑</button>
			<button class="fab-btn" @click="nextUnanswered">跳未答</button>
		</view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				levels: ['16题','48题','96题'],
				levelIndex: 0,
				questions: [],
				answers: {},
				loading: true,
				error: '',
				startTs: Date.now(),
				useCloud: true,
				submitting: false
			}
		},
		computed: {
			levelLabel(){ return this.levels[this.levelIndex] },
			levelKey(){ return (['low','medium','high'])[this.levelIndex] },
			allAnswered() { return this.questions.length > 0 && Object.keys(this.answers).length === this.questions.length },
			answeredCount(){ return Object.keys(this.answers).length },
			progressPct(){ return this.questions.length ? Math.round(this.answeredCount / this.questions.length * 100) : 0 }
		},
		watch: { levelIndex(){ this.loadQuestions() } },
		onLoad() { this.loadQuestions() },
		methods: {
			getTargetCount(){ return ({ low: 16, medium: 48, high: 96 })[this.levelKey] || 16 },
			applyTargetCount(list){ const tgt = this.getTargetCount(); if (Array.isArray(list)) { return list.slice(0, Math.min(tgt, list.length)) } return [] },
			async loadQuestions() {
				this.loading = true
				this.answers = {}
				try {
					if (this.useCloud && uniCloud) {
						await uniCloud.callFunction({ name: 'get-config' })
						const res = await uniCloud.callFunction({ name: 'get-mbti', data: { level: this.levelKey } })
						if (res && res.result && res.result.data && Array.isArray(res.result.data.questions) && res.result.data.questions.length) {
							this.questions = this.applyTargetCount(res.result.data.questions)
							this.loading = false
							this.startTs = Date.now()
							return
						}
					}
				} catch(e) {}
				const map = { low: '/static/mbti_questions_low.json', medium: '/static/mbti_questions_medium.json', high: '/static/mbti_questions_high.json' }
				const url = map[this.levelKey]
				uni.request({ url, header:{'content-type':'application/json'}, success: (res)=>{
					if (res.statusCode===200 && res.data && Array.isArray(res.data.questions)) this.questions = this.applyTargetCount(res.data.questions)
				}, complete: ()=>{ this.loading=false; this.startTs = Date.now() } })
			},
			onAnswerChange(qid, value) { this.$set(this.answers, qid, String(value)) },
			scaleLabel(v) { return ({1:'非常不同意',2:'不同意',3:'中立',4:'同意',5:'非常同意'})[v] },
			nextUnanswered(){
				if (!this.questions.length) return
				const unanswered = this.questions.find(q => !(q.id in this.answers))
				if (!unanswered) { uni.showToast({ title:'已全部作答', icon:'none' }); return }
				this.scrollToQuestion(unanswered.id)
			},
			scrollToQuestion(qid){
				try{
					const query = uni.createSelectorQuery().in(this)
					query.select('#q_'+qid).boundingClientRect()
					query.selectViewport().scrollOffset()
					query.exec(res => {
						const rect = res && res[0]
						const viewport = res && res[1]
						if (!rect || !viewport) return
						const offset = 120 // 顶部安全偏移
						const target = Math.max(0, rect.top + viewport.scrollTop - offset)
						uni.pageScrollTo({ scrollTop: target, duration: 300 })
					})
				}catch(e){}
			},
			goTop(){ uni.pageScrollTo({ scrollTop: 0, duration: 300 }) },
			submit() {
				if (!this.allAnswered) { uni.showToast({ title:'还有题目未作答', icon:'none' }); return }
				if (this.submitting) { return }
				const durationSec = (Date.now() - this.startTs) / 1000
				if (durationSec < 60) {
					uni.showModal({ title: '提示', content: '作答较快，建议认真作答以获得更准确结果。是否继续提交？', success: (r)=>{ if (r.confirm) this.finish() } })
					return
				}
				this.finish()
			},
			finish() {
				this.submitting = true
				const durationSec = (Date.now() - this.startTs) / 1000
				const scoringMap = { '1': -2, '2': -1, '3': 0, '4': +1, '5': +2 }
				const dims = { EI: 0, SN: 0, TF: 0, JP: 0 }
				const counts = { EI: 0, SN: 0, TF: 0, JP: 0 }
				for (const q of this.questions) {
					const val = this.answers[q.id]
					const base = scoringMap[val]
					const score = (q.polarity === -1 ? -base : base)
					dims[q.dimension] += score
					counts[q.dimension] += 1
				}
				const norm = {}
				for (const key of Object.keys(dims)) {
					const n = counts[key]
					const min = n * -2
					const max = n * 2
					const pct = Math.round(((dims[key] - min) / (max - min)) * 100)
					norm[key] = Math.max(0, Math.min(100, pct))
				}
				const type = `${norm.EI>=50?'E':'I'}${norm.SN>=50?'N':'S'}${norm.TF>=50?'F':'T'}${norm.JP>=50?'P':'J'}`
				const result = { type, dimensions: norm, createdAt: Date.now(), level: this.levelKey, version: 1, qc: { durationSec } }
				try {
					const key = 'mbti_history'
					const old = uni.getStorageSync(key) || []
					old.push(result)
					while (old.length > 50) old.shift()
					uni.setStorageSync(key, old)
					uni.setStorageSync('last_mbti_result', result)
				} catch(e) {}
				// 导航容错：优先 navigateTo，失败则 redirectTo
				try {
					uni.navigateTo({ url: '/pages/result/index', fail: ()=>{ uni.redirectTo({ url: '/pages/result/index' }) }, complete: ()=>{ this.submitting = false } })
				} catch(e) {
					this.submitting = false
					uni.redirectTo({ url: '/pages/result/index' })
				}
			}
		}
	}
</script>

<style lang="scss">
	.page { padding: 0 24rpx 24rpx; }
	.header { margin-bottom: 20rpx; }
	.title { font-size: 36rpx; color: $brand-color-heading; }
	.level { display:flex; align-items:center; gap: 12rpx; margin: 8rpx 0; }
	.picker { padding: 8rpx 12rpx; border: 1rpx solid $brand-color-border; border-radius: $brand-radius-md; }
	.sub { font-size: 24rpx; color: $brand-color-muted; }
	/* 进度条 */
	.progress { display:flex; align-items:center; gap: 12rpx; margin: 8rpx 0 16rpx; }
	.progress-sticky { position: sticky; top: 0; z-index: 2; padding: 8rpx 0; background: linear-gradient(180deg, #fff, rgba(255,255,255,0.85)); backdrop-filter: blur(2px); }
	.progress-text { font-size: 24rpx; color: $brand-color-muted; }
	.progress-track { flex:1; height: 12rpx; background: $brand-color-border; border-radius: $brand-radius-sm; overflow: hidden; }
	.progress-fill { height: 100%; background: $brand-color-primary; transition: width $brand-dur-med $brand-ease-standard; }
	.loading { color: $brand-color-muted; padding: 24rpx; }
	.q-card { background: #FFFFFF; border-radius: $brand-radius-lg; padding: 20rpx; margin-bottom: 16rpx; box-shadow: $brand-shadow-card; border: 1rpx solid $brand-color-border; }
	.q-card.answered { border-color: $brand-color-primary; background: linear-gradient(180deg, rgba(107,91,149,0.05), #fff 60%); }
	.q-head { display:flex; align-items:flex-start; gap: 12rpx; margin-bottom: 12rpx; }
	.badge { width: 40rpx; height: 40rpx; border-radius: 9999rpx; background: $brand-color-primary; color: #fff; font-size: 24rpx; display:flex; align-items:center; justify-content:center; box-shadow: 0 4rpx 10rpx rgba(107,91,149,0.25); flex: 0 0 auto; }
	.q-text { flex: 1; line-height: 1.6; color: $brand-color-heading; }
	.scale { display: flex; justify-content: space-between; gap: 12rpx; margin-top: 12rpx; }
	.scale-item { display: flex; align-items: stretch; flex: 1; min-width: 0; }
	.scale-radio { position: absolute; opacity: 0; width: 0; height: 0; }
	.chip { display:flex; align-items:center; justify-content:center; width: 100%; min-height: 72rpx; padding: 12rpx 20rpx; border-radius: 9999rpx; border: 1rpx solid $brand-color-border; background: #FFFFFF; color: $brand-color-text; transition: background $brand-dur-fast $brand-ease-standard, color $brand-dur-fast $brand-ease-standard, border-color $brand-dur-fast $brand-ease-standard, box-shadow $brand-dur-fast $brand-ease-standard; text-align: center; white-space: normal; word-break: break-word; overflow-wrap: anywhere; position: relative; font-size: 26rpx; line-height: 1.2; box-sizing: border-box; }
	.chip.active { background: linear-gradient(135deg, $brand-color-primary, mix($brand-color-primary, #fff, 35%)); color: #fff; border-color: transparent; box-shadow: 0 4rpx 12rpx rgba(107,91,149,0.25); padding-left: 36rpx; }
	.chip.active::after { content: '✓'; position: absolute; left: 16rpx; top: 50%; transform: translateY(-50%); font-size: 24rpx; opacity: 0.9; }
	.actions { position: sticky; bottom: 0; padding: 16rpx 0 12rpx; background: linear-gradient(180deg, rgba(255,255,255,0), $brand-color-bg 60%); display:flex; justify-content:center; }
	.btn-wide { width: 72%; max-width: 560rpx; }
	button[disabled] { opacity: 0.6; }
	/* 悬浮操作按钮 */
	.fab { position: fixed; right: 24rpx; bottom: calc(24rpx + env(safe-area-inset-bottom)); bottom: calc(24rpx + constant(safe-area-inset-bottom)); display: flex; flex-direction: column; gap: 16rpx; z-index: 10; }
	.fab-btn { min-width: 96rpx; height: 96rpx; padding: 0 20rpx; border-radius: 9999rpx; background: #fff; color: $brand-color-primary; border: 1rpx solid $brand-color-border; box-shadow: $brand-shadow-card; display:flex; align-items:center; justify-content:center; }
	/* 强制按钮居中（保障多端一致） */
	.actions .btn { align-self: center; }
	.btn-wide { margin: 0 auto; }
</style> 